#ifndef UDP_SOCKET_H
#define UDP_SOCKET_H

#include "xict_cpp/bridge/callbacks.h"
#include <boost/asio.hpp>
#include <iostream>
#include <thread>

#define BUF_SIZE 8 * 1024

namespace bridge {
using Udp = boost::asio::ip::udp;
using boost::asio::deadline_timer;

class UdpSocket {
public:
    UdpSocket(const UdpSocket&);

    UdpSocket& operator=(const UdpSocket&);

    /** server **/
    UdpSocket(boost::asio::io_service& io_service, short port,
              bool auto_receive = true);

    /** client **/
    UdpSocket(boost::asio::io_service& io_service, const std::string& host,
              short port, bool auto_receive = true);

    void CheckDeadline();

    ~UdpSocket();

    void DoAsyncRead();

    //        void doRead();

    /** callbacks **/
    void SetMessageCallback(const UdpMessageCallback& cb) {
        messageCallback_ = cb;
    }

    void SetWriteCompleteCallback(const UdpWriteCompleteCallback& cb) {
        writeCompleteCallback_ = cb;
    }

    void OnMessage(const boost::system::error_code& error, size_t len);

    void OnWriteComplete(const boost::system::error_code& error, size_t len);

    /** read && write **/
    void AsyncSend(const void* data, size_t len);

    void AsyncSend(const std::string& content);

    bool Send(const uint8_t* data, size_t len);

    bool Send(const std::string& content);

    void AsyncReceive();

    size_t Receive(void* data);

private:
    boost::asio::io_service& ioService;
    Udp::socket socket_;
    Udp::endpoint endpoint_;
    // Udp::endpoint senderEndpoint_;
    deadline_timer deadline_;

    UdpMessageCallback messageCallback_;
    UdpWriteCompleteCallback writeCompleteCallback_;

    // std::array<uint8_t, BUF_SIZE> recvBuffer_;
    char recvBuffer_[BUF_SIZE];
};
}   // namespace bridge
#endif   // UDP_SOCKET_H
